import 'package:http/http.dart';
import 'package:backend.purchases/domain/clients/app_store_api_client.dart';
import 'package:backend.purchases/domain/entities/app_store_api/app_store_api_access_token.dart';
import 'package:backend.purchases/domain/use_cases/issue_app_store_api_access_token/use_case.dart';

Future<AppStoreApiClient> createAppStoreApiClient({
  required Client baseClient,
  required IssueAppStoreApiAccessToken issueAppStoreApiAccessToken,
}) async {
  final accessToken = await issueAppStoreApiAccessToken();

  return _AppStoreApiClientImpl(
    accessToken: accessToken,
    baseClient: baseClient,
    issueAppStoreApiAccessToken: issueAppStoreApiAccessToken,
  );
}

class _AppStoreApiClientImpl extends BaseClient implements AppStoreApiClient {
  _AppStoreApiClientImpl({
    required this.accessToken,
    required Client baseClient,
    required IssueAppStoreApiAccessToken issueAppStoreApiAccessToken,
  })  : _baseClient = baseClient,
        _issueAppStoreApiAccessToken = issueAppStoreApiAccessToken;

  final Client _baseClient;
  final IssueAppStoreApiAccessToken _issueAppStoreApiAccessToken;

  @override
  AppStoreApiAccessToken accessToken;

  @override
  Future<StreamedResponse> send(BaseRequest request) async {
    final modifiedRequest = _RequestOverride(request);

    if (accessToken.isExpired) {
      accessToken = await _issueAppStoreApiAccessToken();
    }

    _setAuthorizationHeader(
      request: modifiedRequest,
      accessToken: accessToken,
    );

    final response = await _baseClient.send(modifiedRequest);

    if (response.statusCode == 401) {
      accessToken = await _issueAppStoreApiAccessToken();

      _setAuthorizationHeader(
        request: modifiedRequest,
        accessToken: accessToken,
      );

      return _baseClient.send(modifiedRequest);
    }

    return response;
  }

  void _setAuthorizationHeader({
    required BaseRequest request,
    required AppStoreApiAccessToken accessToken,
  }) {
    request.headers['Authorization'] = 'Bearer ${accessToken.data}';
  }
}

class _RequestOverride extends BaseRequest {
  _RequestOverride(BaseRequest baseRequest) : super(baseRequest.method, baseRequest.url) {
    _baseRequestFinalizationStream = baseRequest.finalize();
    headers.addAll(baseRequest.headers);
  }

  late final ByteStream _baseRequestFinalizationStream;

  @override
  ByteStream finalize() {
    super.finalize();
    return _baseRequestFinalizationStream;
  }
}
